'''
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License") you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
'''

# package org.apache.jena.datatypes.xsd.impl
#
# import java.math.BigDecimal
# import java.math.BigInteger
#
# import org.apache.jena.datatypes.*
# import org.apache.jena.datatypes.xsd.*
# import org.apache.jena.graph.impl.LiteralLabel
# import org.apache.jena.shared.impl.JenaParameters

'''
 * Base implementation for all numeric datatypes derived from
 * xsd:decimal. The only purpose of this place holder is
 * to support the isValidLiteral tests across numeric types.
 * * <p>Note that float and double are not included in this set.
'''
# from base.datatypes.BaseDatatype import BaseDatatype
from base.datatypes.xsd.XSDDatatype import XSDDatatype

class XSDBaseNumericType(XSDDatatype):

    '''
     * Constructor.
     *
     * @param typeName the name of the XSD type to be instantiated, this is
     *                 used to lookup a type definition from the Xerces schema factory.
    '''
    # param
    # return
    def __init__(self, typename):
        super().__init__(typename)

    '''
     * Constructor.
     *
     * @param typeName  the name of the XSD type to be instantiated, this is
     *                  used to lookup a type definition from the Xerces schema factory.
     * @param javaClass the java class for which this xsd type is to be
     *                  treated as the cannonical representation
    '''
    # param
    # return
    # XSDBaseNumericType(String typeName, Class<?> javaClass):
    #     super(typeName, javaClass)
    


    '''
     * Test whether the given LiteralLabel is a valid instance
     * of this datatype. This takes into account typing information
     * as well as lexical form - for example an xsd:string is
     * never considered valid as an xsd:integer (even if it is
     * lexically legal like "1").
    '''
    #@Override
    # param LiteralLabel
    # return boolean
    def isValidLiteral(self, lit):
        if (super().isBaseTypeCompatible(lit)):
            # String
            lex = lit.getLexicalForm()
            # 默认为false
            # if (JenaParameters.enableWhitespaceCheckingOfTypedLiterals):
            #     if (lex.trim().equals(lex)):
            #         return isValid(lit.getLexicalForm())
            #      else:
            #         return false
            #
            #  else:
            return self.isValid(lit.getLexicalForm())
        else:
            return False
        
    

    '''
     * Test whether the given object is a legal value form
     * of this datatype. Brute force implementation.
    '''
    #@Override
    # param Object
    # return boolean
    def isValidValue(self, valueForm):
        # TODO 这个方法不一定靠谱
        if str(valueForm).isnumeric():
            return self.isValid(self.unparse(valueForm))
        else:
            return False
        
    

    '''
     * Cannonicalise a java Object value to a normal form.
     * Primarily used in cases such as xsd:integer to reduce
     * the Java object representation to the narrowest of the Number
     * subclasses to ensure that indexing of typed literals works.
    '''
    #@Override
    # param Object
    # return Object
    def cannonicalise(self, value):
        # if (value instanceof BigInteger):
        #     return cannonicalizeInteger((BigInteger) value)
        # else if (value instanceof BigDecimal):
        #     return cannonicalizeDecimal((BigDecimal) value)
        # return suitableInteger(((Number) value).longValue())
        return value
    
    # BigInteger
    # ten = BigInteger("10")
    # int
    QUOT = 0
    # int
    REM = 1

    '''
     * Cannonicalize a big decimal
    '''
    # private Object cannonicalizeDecimal(BigDecimal value):
    #     # This could can be simplified by using toBigIntegerExact
    #     if (value.scale() > 0):
    #         # Check if we can strip off any trailing zeros after decimal point
    #         BigInteger i = value.unscaledValue()
    #         int limit = value.scale()
    #         int nshift = 0
    #         for (nshift = 0 nshift < limit nshift++):
    #             BigInteger[] quotRem = i.divideAndRemainder(ten)
    #             if (quotRem[REM].intValue() != 0) break
    #             i = quotRem[QUOT]
    #
    #         if (nshift > 0):
    #             value = BigDecimal(i, limit - nshift)
    #             if (value.scale() <= 0):
    #                 return cannonicalizeInteger(value.toBigInteger())
    #
    #
    #         return value
    #      else:
    #         return cannonicalizeInteger(value.toBigInteger())
        
    

    '''
     * Cannonicalize a big integer
    '''
    # private Object cannonicalizeInteger(BigInteger value):
    #     if (value.bitLength() > 63):
    #         return value
    #      else:
    #         return suitableInteger(value.longValue())
        
    

    '''
     * Parse a lexical form of this datatype to a value
     *
     * @throws DatatypeFormatException if the lexical form is not legal
    '''
    #@Override
    # param String
    # return Object
    # throws DatatypeFormatException
    def parse(self, lexicalForm):
        self.checkWhitespace(lexicalForm)
        return super().parse(lexicalForm)
    

    '''
     * Convert a value of this datatype to lexical form.
     * Certain forms are not a simple matter of java's toString on the Number object.
    '''
    #@Override
    # param Object
    # return String
    def unparse(self, value):
        # 这里注释原有的逻辑
        # if (value instanceof BigDecimal)
        #     # Avoid exponent usage.
        #     return ((BigDecimal) value).toPlainString()
        # See also for XSDfloat and XSDdouble. 
        # Integer hierarchy is OK.
        return str(value)
    

    '''
     * Check for whitespace violations.
     * Turned off by default.
    '''
    # param String
    # return void
    def checkWhitespace(self, lexicalForm):
        # 这里注释原有的逻辑
        # if (JenaParameters.enableWhitespaceCheckingOfTypedLiterals):
        #     if (!lexicalForm.trim().equals(lexicalForm)):
        #         throw DatatypeFormatException(lexicalForm, this, "whitespace violation")
        pass

    '''
     * Compares two instances of values of the given datatype.
    '''
    #@Override
    # param LiteralLabel LiteralLabel
    # return boolean
    def isEqual(self, value1, value2):
        if isinstance(value1.getDatatype(), XSDBaseNumericType) and isinstance(value2.getDatatype(), XSDBaseNumericType):
            # 这里注释了BigDecimal 的比较
            # Number n1 = (Number) value1.getValue()
            # Number n2 = (Number) value2.getValue()
            # if (n1 instanceof BigDecimal && n2 instanceof BigDecimal):
            #     return ((BigDecimal) n1).compareTo((BigDecimal) n2) == 0
            return value1.getValue() == value2.getValue()
        else:
            # At least one arg is not part of the integer hierarchy
            return False
        
    

